using System.Linq;
using System.Web.Security;
using System.Configuration.Provider;
using System.Collections.Specialized;
using System;
using BLToolkit.Data.Linq;
using Calendar.Logic.ObjectManager;
using Calendar.Logic.ObjectManager.Authorization;
using Calendar.Logic.ObjectModel.Authorization;

/* CONVERTED TO PostgreSQL on 9-14-2006 by Lee@woodchop.com - http://blog.woodchop.com
 * BASED ON THE ORIGINAL MySQL IMPLEMENTATION BY Andri (see original comments below)
 */

/* 
-- Please, send me an email (andriniaina@gmail.com) if you have done some improvements or bug corrections to this file
      or leave your modifications on the comments page on sprinj.com
	  
*/

namespace Calendar.Logic.Core
{

	public sealed class PostgreSqlRoleProvider : RoleProvider
	{

		//
		// Global connection string, generic exception message, event log info.
		//

		//private const string rolesTable = "provider_roles";
		//private const string usersInRolesTable = "provider_usersinroles";
		//private ConnectionStringSettings pConnectionStringSettings;
		//private string connectionString;


		//
		// System.Configuration.Provider.ProviderBase.Initialize Method
		//
		public override void Initialize(string name, NameValueCollection config)
		{
			//
			// Initialize values from web.config.
			//

			if (config == null)
				throw new ArgumentNullException("config");

			if (name == null || name.Length == 0)
				name = "PostgreSqlRoleProvider";

			if (String.IsNullOrEmpty(config["description"]))
			{
				config.Remove("description");
				config.Add("description", "Sample PostgreSql Role provider");
			}

			// Initialize the abstract base class.
			base.Initialize(name, config);

			if (config["applicationName"] == null || config["applicationName"].Trim() == "")
			{
				pApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
			}
			else
			{
				pApplicationName = config["applicationName"];
			}

            //GlobalContext.Instance.ApplicationName = pApplicationName;
		}



		//
		// System.Web.Security.RoleProvider properties.
		//
		private string pApplicationName;
		public override string ApplicationName
		{
			get { return pApplicationName; }
			set { pApplicationName = value; }
		}

		//
		// RoleProvider.AddUsersToRoles
		//
		public override void AddUsersToRoles(string[] usernames, string[] rolenames)
		{
			foreach (string rolename in rolenames)
			{
				if (!RoleExists(rolename))
				{
					throw new ProviderException("Role name not found.");
				}
			}

			foreach (var username in usernames)
			{
				if (username.IndexOf(',') > 0)
				{
					throw new ArgumentException("User names cannot contain commas.");
				}

				foreach (var rolename in rolenames)
				{
					if (IsUserInRole(username, rolename))
					{
						throw new ProviderException("User is already in role.");
					}
				}
			}

            try
            {
                //GlobalContext.Instance.DbManager.BeginTransaction();
                foreach (var username in usernames)
                {
                    var user = UserManager.Table.SelectByName(username.ToLower()).FirstOrDefault();
                    if(user == null) continue;

                    foreach (var rolename in rolenames)
                    {
                        var role = RoleManager.Table.SelectByName(rolename).FirstOrDefault();
                        if(role == null) continue;

                        UserRoleManager.Table.Value(user.ID, role.ID).Insert();
                    }
                }
                //GlobalContext.Instance.DbManager.CommitTransaction();
            }
            catch(Exception)
            {   
            }
		}



		//
		// RoleProvider.CreateRole
		//

		public override void CreateRole(string rolename)
		{
			if (rolename.IndexOf(',') > 0)
			{
				throw new ArgumentException("Role names cannot contain commas.");
			}

			if (RoleExists(rolename))
			{
				throw new ProviderException("Role name already exists.");
			}

            try
            {
                RoleManager.Table.
                    Value(r => r.Rolename, rolename).
                    Value(r => r.ApplicationName, ApplicationName).
                    Insert();
            }
            catch(Exception)
            {      
            }
		}


		//
		// RoleProvider.DeleteRole
		//
		public override bool DeleteRole(string rolename, bool throwOnPopulatedRole)
		{
			if (!RoleExists(rolename))
			{
				throw new ProviderException("Role does not exist.");
			}

			if (throwOnPopulatedRole && GetUsersInRole(rolename).Length > 0)
			{
				throw new ProviderException("Cannot delete a populated role.");
			}
            try
            {
                UserRoleManager.Table.Where(x => x.ScnEntity.Rolename == rolename).Delete();
                RoleManager.Table.Where(x => x.Rolename == rolename).Delete();
            }
            catch(Exception)
            {
            }

		    return true;
		}


		//
		// RoleProvider.GetAllRoles
		//

		public override string[] GetAllRoles()
		{
            try
            {
                return RoleManager.Table.SelectByApp().Select(role => role.Rolename).ToArray();
            }
            catch(Exception)
		    {
                return new string[0];
		    }
		}


		//
		// RoleProvider.GetRolesForUser
		//
		public override string[] GetRolesForUser(string username)
		{
            try
            {
                return UserRoleManager.Table.SelectRolesByUser(username.ToLower()).Select(r => r.Rolename).ToArray();
            }
            catch (Exception)
            {
                return new string[0];
            }
		}


		//
		// RoleProvider.GetUsersInRole
		//
		public override string[] GetUsersInRole(string rolename)
        {
            try
            {
                return UserRoleManager.Table.SelectUsersByRole(rolename).Select(u => u.Username).ToArray();
            }
            catch (Exception)
            {
                return new string[0];
            } 
		}


		//
		// RoleProvider.IsUserInRole
		//
		public override bool IsUserInRole(string username, string rolename)
		{
            try
            {
                return UserRoleManager.Table.ExistsUserInRole(username.ToLower(), rolename);
            }
            catch (Exception)
            {
                return false;
            }
		}


		//
		// RoleProvider.RemoveUsersFromRoles
		//
		public override void RemoveUsersFromRoles(string[] usernames, string[] rolenames)
		{
			foreach (string rolename in rolenames)
			{
				if (!RoleExists(rolename))
				{
					throw new ProviderException("Role name not found.");
				}
			}

			foreach (string username in usernames)
			{
				foreach (string rolename in rolenames)
				{
					if (!IsUserInRole(username, rolename))
					{
						throw new ProviderException("User is not in role.");
					}
				}
			}

            try
            {
                //GlobalContext.Instance.DbManager.BeginTransaction();
                foreach (var username in usernames)
                {
                    var user = UserManager.Table.SelectByName(username.ToLower()).FirstOrDefault();
                    if (user == null) continue;

                    foreach (var rolename in rolenames)
                    {
                        var role = RoleManager.Table.SelectByName(rolename).FirstOrDefault();
                        if (role == null) continue;
                        UserRoleManager.Table.Select<UserRole, User, Role>(user.ID, role.ID).Delete();
                    }
                }
                //GlobalContext.Instance.DbManager.CommitTransaction();
            }
            catch(Exception)
		    {
		    }
		}


		//
		// RoleProvider.RoleExists
		//

		public override bool RoleExists(string rolename)
		{
            try
            {
		        return RoleManager.Table.SelectByName(rolename).Count() > 0;
            }
            catch (Exception)
            {
                return false;
            }
		}

		//
		// RoleProvider.FindUsersInRole
		//

		public override string[] FindUsersInRole(string rolename, string usernameToMatch)
		{
            try
            {
                return UserRoleManager.Table.SelectUsersByRole(rolename).SelectByNameToMatch(usernameToMatch.ToLower()).Select(role => role.Username).ToArray();
            }
            catch (Exception)
            {
                return new string[0];
            } 
        }
	}
}